package org.hugh.trade.service.impl;

import org.hugh.trade.common.TradeDirectEnum;
import org.hugh.trade.model.EntrustOrder;
import org.hugh.trade.service.MatchEngine;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * 交易撮合引擎
 */
@Service
public class MatchEngineImpl implements MatchEngine {

    // PriorityBlockingQueue 是线程安全的
    private final Map<String, PriorityBlockingQueue<EntrustOrder>> buyOrders;
    private final Map<String, PriorityBlockingQueue<EntrustOrder>> sellOrders;

    public MatchEngineImpl() {
        this.buyOrders = new HashMap<>();
        this.sellOrders = new HashMap<>();
    }

    @Override
    public void placeOrder(EntrustOrder order) {
        if (TradeDirectEnum.BUY.name().equals(order.getDirect())) {
            buyOrders.putIfAbsent(order.getSecCode(), new PriorityBlockingQueue<>(
                    16, Comparator.comparing(EntrustOrder::getPrice).reversed()
                    .thenComparing(EntrustOrder::getTimestamp)
            ));
            buyOrders.get(order.getSecCode()).add(order);
        } else {
            sellOrders.putIfAbsent(order.getSecCode(), new PriorityBlockingQueue<>(
                    16, Comparator.comparing(EntrustOrder::getPrice)
                    .thenComparing(EntrustOrder::getTimestamp)
            ));
            sellOrders.get(order.getSecCode()).add(order);
        }
        matchOrder(order.getSecCode());
    }

    @Override
    public void matchOrder(String secCode) {

        PriorityBlockingQueue<EntrustOrder> buyQueue = buyOrders.get(secCode);
        PriorityBlockingQueue<EntrustOrder> sellQueue = sellOrders.get(secCode);

        if (buyQueue == null || sellQueue == null) return;

        while (!buyQueue.isEmpty() && !sellQueue.isEmpty()) {
            EntrustOrder buyOrder = buyQueue.peek();
            EntrustOrder sellOrder = sellQueue.peek();

            if (buyOrder.getPrice().compareTo(sellOrder.getPrice()) >= 0) {
                int tradeQuantity = Math.min(buyOrder.getEntrustQty(), sellOrder.getEntrustQty());
                BigDecimal tradePrice = sellOrder.getPrice();

                buyOrder.setEntrustQty(buyOrder.getEntrustQty() - tradeQuantity);
                sellOrder.setEntrustQty(sellOrder.getEntrustQty() - tradeQuantity);

                System.out.println("成交: " + tradeQuantity + " 股 " + secCode + " @ " + tradePrice);

                if (buyOrder.getEntrustQty() == 0) buyQueue.poll();
                if (sellOrder.getEntrustQty() == 0) sellQueue.poll();
            } else {
                break;
            }
        }
    }

}
